// 函数中的this指向和当前函数在哪定义的或者在哪执行的都没有任何的关系
// 分析this指向的规律如下:

// [非严格模式]
// 1、自执行函数中的this永远是window
//  [案例1]
var obj = {
    fn: (function (i) {
        //this->window
        return function () {
            //this->obj
        }
    })(0)
};
obj.fn();

// 2、给元素的某个行为绑定一个方法,当行为触发的时候,执行绑定的方法,此时方法中的this是当前的元素
//  [案例1]
oDiv.onclick = function () {
    //this->oDiv
};

// [案例2]
function fn() {
    //this->window
}

oDiv.onclick = function () {
    //this->oDiv
    fn();
};
// 3、方法执行,看方法名前面是否有".",有的话,"."前面是谁this就是谁,没有的话this就是window
//  [案例1]
var obj = {fn: fn};

function fn() {
}

fn.prototype.aa = function () {
};
var f = new fn;

fn();//this->window
obj.fn();//this->obj
fn.prototype.aa();//this->fn.prototype
f.aa();//this->f
f.__proto__.aa();//this->f.__proto__->fn.prototype


// 4、在构造函数模式中,函数体中的this.xxx=xxx中的this是当前类的一个实例
//  [案例1]
function Fn() {
    this.x = 100; //this->f
    this.getX = function () {
        console.log(this);//this->f 因为getX方法执行的时候,"."前面是f,所以this是f
    }
}

var f = new Fn;
f.getX();


// 5、使用call/apply来改变this的指向(一但遇到call/apply上述的四条都没用了)
// call, apply都属于Function.prototype的一个方法,它是JavaScript引擎内在实现的,因为属于Function.prototype,所以每个Function对象实例,也就是每个方法都有call, apply属性.既然作为方法的属性,那它们的使用就当然是针对方法的了.这两个方法是容易混淆的,因为它们的作用一样,只是使用方式不同.
// 这两个属性的区别
// 相同点:两个方法产生的作用是完全一样的
// 不同点:方法传递的参数不同
// apply与call产生的作用是一样的,可以说
// call, apply作用就是借用别人的方法来调用,就像调用自己的一样
// this是javascript的一个关键字，随着函数使用场合不同，this的值会发生变化。但是总有一个原则，那就是this指的是调用函数的那个对象，通过本文给大家介绍JS中改变this指向的方法(call和apply、bind)，需要的朋友参考下
// this是javascript的一个关键字，随着函数使用场合不同，this的值会发生变化。但是总有一个原则，那就是this指的是调用函数的那个对象。
// this一般指向的是当前被调用者，但也可以通过其它方式来改变它的指向，下面将介绍三种方式：


// 1.call用作继承时：

function Parent(age) {
    this.name = ['mike', 'jack', 'smith'];
    this.age = age;
}

function Child(age) {
    Parent.call(this, age);//把this指向Parent,同时还可以传递参数
}

var test = new Child(21);
console.log(test.age);//21
console.log(test.name);
test.name.push('bill');
console.log(test.name);//mike,jack,smith,bill
//2. call和apply都可以改变this指向，不过apply的第二个参数是散列分布，call则可以是一个数组
console.log(Math.max.apply(null, [1, 2, 3, 4]));//4
// apply() 方法接收两个参数：一个是在其中运行函数的作用域，另一个是参数数组。其中，第二个参数可以是 Array 的实例，也可以是arguments 对象。call() 方法与 apply() 方法的作用相同，它们的区别仅在于接收参数的方式不同。对于 call()
// 方法而言，第一个参数是 this 值没有变化，变化的是其余参数都直接传递给函数。换句话说，在使用call() 方法时，传递给函数的参数必须逐个列举出来。
// 3.ES5还定义了一个方法：bind()，它会创建一个函数的实例，其this值会被绑定到传给bind()函数的值。如
window.color = 'red';
var o = {color: 'blue'};

function sayColor() {
    console.log(this.color);
}

var objectSaycolor = sayColor.bind(o);
//var objectSaycolor=sayColor.bind();
// objectSaycolor();//blue
// 在这里sayColor()调用bind()并传入对象o,创建了objectSayColor()函数。objectSayColor()函数的this值等于o,因此即使是在全局作用域中调用这个函数，也会看到blue。
// 以上所述是小编给大家介绍的JS中改变this指向的方法(call和apply、bind)，希望对大家以上帮助！


// 下面还有点时间给大家补充点基础知识有关：call()与apply()区别
// 一、方法的定义
// call方法:
// 语法：call(thisObj，Object)
// 定义：调用一个对象的一个方法，以另一个对象替换当前对象。
// 说明：
// call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
// 如果没有提供 thisObj 参数，那么 Global 对象被用作 thisObj。
// apply方法：
// 语法：apply(thisObj，[argArray])
// 定义：应用某一对象的一个方法，用另一个对象替换当前对象。
// 说明：
// 如果 argArray 不是一个有效的数组或者不是 arguments 对象，那么将导致一个 TypeError。
// 如果没有提供 argArray 和 thisObj 任何一个参数，那么 Global 对象将被用作 thisObj， 并且无法被传递任何参数。
// 代码示例：
function Animal(name) {
    this.name = name;
    this.showName = function () {
        console.log(this.name);
    };
}

function Cat(name) {
    Animal.call(this, name);
}

Cat.prototype = new Animal();

function Dog(name) {
    Animal.apply(this, name);
}

Dog.prototype = new Animal();
var cat = new Cat("Black Cat"); //call必须是object
var dog = new Dog(["Black Dog"]); //apply必须是array
cat.showName();
dog.showName();
console.log(cat instanceof Animal);
console.log(dog instanceof Animal);
模拟call, apply的this替换

function Animal(name) {
    this.name = name;
    this.showName = function () {
        alert(this.name);
    };
};

function Cat(name) {
    this.superClass = Animal;
    this.superClass(name);
    delete superClass;
}

var cat = new Cat("Black Cat");
cat.showName();

// 要着重讲下，记住构造函数被new操作，要让new正常作用最好不能在构造函数里写return，没有return的构造函数都是按上面四点执行，有了return情况就复杂了，这个知识我会在讲prototype时候讲到。

// 　　Javascript还有一种方式可以改变this指针，这就是call方法和apply方法，call和apply方法的作用相同，就是参数不同，call和apply的第一个参数都是一样的，但是后面参数不同，apply第二个参数是个数组，call从第二个参数开始后面有许多参数。Call和apply的作用是什么，这个很重要，重点描述如下：

// 　　Call和apply是改变函数的作用域（有些书里叫做改变函数的上下文）

// 　　这个说明我们参见上面new操作符第二条：

// 　　将构造函数的作用域赋给新对象（因此this就指向了这个新对象）；

// 　　Call和apply是将this指针指向方法的第一个参数。

// 　　我们看看下面的代码：


var name = "sharpxiajun";

function ftn(name) {
    console.log(name);
    console.log(this.name);
    console.log(this);
}

ftn("101");
var obj = {
    name: "xtq"
};
ftn.call(obj, "102");

// 　　我们看到apply和call改变的是this的指向，这点在开发里很重要，开发里我们常常被this所迷惑，迷惑的根本原因我在上文讲到了，这里我讲讲表面的原因：

// 　　表面原因就是我们定义对象使用对象的字面表示法，字面表示法在简单的表示里我们很容易知道this指向对象本身，但是这个对象会有方法，方法的参数可能会是函数，而这个函数的定义里也可能会使用this指针，如果传入的函数没有被实例化过和被实例化过，this的指向是不同，有时我们还想在传入函数里通过this指向外部函数或者指向被定义对象本身，这些乱七八糟的情况使用交织在一起导致this变得很复杂，结果就变得糊里糊涂。

// 　　其实理清上面情况也是有迹可循的，就以定义对象里的方法里传入函数为例：

// 　　情形一：传入的参数是函数的别名，那么函数的this就是指向window；

// 　　情形二：传入的参数是被new过的构造函数，那么this就是指向实例化的对象本身；

// 　　情形三：如果我们想把被传入的函数对象里this的指针指向外部字面量定义的对象，那么我们就是用apply和call

// 　　我们可以通过代码看出我的结论，代码如下：

var name = "I am window";
var obj = {
    name: "sharpxiajun",
    job: "Software",
    ftn01: function (obj) {
        obj.show();
    },
    ftn02: function (ftn) {
        ftn();
    },
    ftn03: function (ftn) {
        ftn.call(this);
    }
};

function Person(name) {
    this.name = name;
    this.show = function () {
        console.log("姓名:" + this.name);
        console.log(this);
    }
}

var p = new Person("Person");
obj.ftn01(p);
obj.ftn02(function () {
    console.log(this.name);
    console.log(this);
});
obj.ftn03(function () {
    console.log(this.name);
    console.log(this);
});


// 　　结果如下：


// 　　最后再总结一下：

// 　　如果在javascript语言里没有通过new（包括对象字面量定义）、call和apply改变函数的this指针，函数的this指针都是指向window的。

// 以上5种是非严格模式下面说一下严格模式情况下
// [严格模式]
"use strict";//->告诉浏览器我们接下来编写的JS代码采用严格模式

// 1、自执行函数中的this永远是undefined
//  [案例]
var obj = {
    fn: (function (i) {
        //this->undefined
        return function () {
            //this->obj
        }
    })(0)
};
obj.fn();

// 3、方法执行,看方法名前面是否有".",有的话,"."前面是谁this就是谁,没有的话this就是undefined
//  [案例]
var obj = {fn: fn};

function fn() {
}

fn();//this->undefined
obj.fn();//this->obj

// 我们发现严格模式下的this相对于非严格模式下的this主要区别在于：对于JS代码中没有写执行主体的情况下,非严格模式下默认都是window执行的,所以this指向的是window;但是在严格的模式下,没有写就是没有执行主体,this指向的是undefined;
